package free.mrchen.boot.gate.server.endpoint;

import free.mrchen.boot.gate.server.def.RouteDef;
import free.mrchen.boot.gate.server.def.RouteDefFeature;
import free.mrchen.boot.gate.server.vo.RVo;
import org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint;
import org.springframework.cloud.context.scope.refresh.RefreshScope;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@RestControllerEndpoint( id = "routeFeature" )
public class RouteFeatureControllerEndpoint {

    private final RefreshScope refreshScope;

    private final RouteDefFeature routeDefFeature;

    public RouteFeatureControllerEndpoint(RefreshScope refreshScope, RouteDefFeature routeDefFeature) {
        this.refreshScope = refreshScope;
        this.routeDefFeature = routeDefFeature;
    }

    @GetMapping("/definitions")
    public Mono<RVo> routeDefinitions() {
        return Flux.fromIterable(routeDefFeature.listFeature().values())
                .collectList()
                .map( RVo::success )
                .map(RVo.Builder::build);
    }

    @GetMapping("/definition/{id}")
    public Mono<RVo> getRouteDefinition(
            @PathVariable("id") String id
    ) {
        return Flux.fromIterable(this.routeDefFeature.listFeature().values())
                .filter( it -> id.equals( it.getId() ))
                .singleOrEmpty()
                .map(RVo::success)
                .map(RVo.Builder::build);
    }


    @DeleteMapping("/definition/{id}")
    public Mono<RVo> deleteRouteDefinition(
            @PathVariable("id") String id
    ) {
        return Mono.just(routeDefFeature.remove(id))
                .map(RVo::success)
                .map(RVo.Builder::build);
    }

    @PostMapping("/definition/{id}")
    public Mono<RVo> addOrReplaceRouteDefinition(
            @PathVariable("id") String id ,
            @RequestBody RouteDef routeDef
    ) {
        routeDef.setId( id );
        return Mono.just(routeDefFeature.addOrReplace( routeDef ))
                .map(RVo::success)
                .map(RVo.Builder::build);
    }

    @PostMapping("/definitions/commit")
    public Mono<RVo> commits() {
        return Mono.just( routeDefFeature.commitAll() ).handle( (it,then) -> {
            refreshScope.refreshAll();
            then.next(it);
        }).map(RVo::success).map(RVo.Builder::build);
    }

    @PostMapping("/definition/{id}/commit")
    public Mono<RVo> commit(
            @PathVariable("id") String id
    ) {
        return Mono.just( routeDefFeature.commit(id) ).handle( (it,then) -> {
            refreshScope.refreshAll();
            then.next( it );
        }).map(RVo::success).map(RVo.Builder::build);
    }

    @PostMapping("/definitions/rollback")
    public Mono<RVo> rollbackAll() {
        return Mono.just( routeDefFeature.rollbackAll() )
                .map(RVo::success)
                .map(RVo.Builder::build);
    }


    @PostMapping("/definition/{id}/rollback")
    public Mono<RVo> rollback(
            @PathVariable("id") String id
    ) {
        return Mono.just( routeDefFeature.rollback(id) )
                .map(RVo::success)
                .map(RVo.Builder::build);
    }
}
